/**
 * Copyright (C) 2008+ Spark Zheng
 *
 * @file	src/threadpool.c
 * @brief 
 *	      A simple compact threadpool. A generate infrastructure.
 *	      -1. tpool init/exit/execute
 *	      -2. tpool wait
 *	      -3. tpool execute/timeout/retrieve
 *
 * @module      dlib
 * @see		dlib
 *
 * @history     
 *		version 0.0.1 initialized by Spark Zheng, implement generate functions
 *		version 0.1.0 modified by Spark Zheng, add gentle wait: dlib_tpool_wait
 *		version 0.2.0 modified by Spark Zheng, tidy it up as generate-utils module
 *		version 0.2.1 modified by Spark Zheng, add detach attribution for each worker
 *		version 0.3.0 modified by Spark Zheng, add result submit queue for pipeline
 *			and add timeout callbacks for task
 */

#include <stdio.h>
#include <unistd.h>
#include "list.h"
#include "threadpool.h"
#include "mempool.h"
#include "timer.h"

/** tpool status */
typedef enum {
	TP_WORK = 1,
	TP_EXIT
} tp_status_t;

#ifdef _DEBUG
struct tstatics {
	uint32_t	count;		/** worker server count(accumulated) */
	struct timeval  tv;		/** worker server time(accumulated) */
};
#endif

struct dtask {
	list_node_t	node;		/** task stack */

	uint32_t	task_nice;	/** task priority */
	void		*task_arg;	/** task function arg */
	dlib_task_fn	task_cb;	/** task function built-in */

	time_t		task_start;	/** task start time */
	int32_t		task_timeout;	/** task timeout number */
	void		*totask_arg;	/** task timeout function argument */
	dlib_totask_fn	totask_cb;	/** task timeout function */

	void		*task_res;	/** result of task */
	void		*detask_arg;	/** task finished function argument */
	dlib_detask_fn	detask_cb;	/** task finished function */
};

struct titem {
	pthread_t	pid;		/** thread item id */
	void		*thread_data;	/** thread special data */

#ifdef _DEBUG
	dlib_tstatics_t	statics;	/** tpool statics for trace/debug */
#endif
};

struct tpool {
	uint32_t	tp_id;		/** identity of tpool */
	tp_status_t	status;		/** tpool status */

	pthread_attr_t	tp_attr;	/** tpool worker attr */

	pthread_mutex_t	worker_mutex;	/** free worker mutex */
	pthread_mutex_t	task_mutex;	/** working task queue mutex */
	pthread_mutex_t	result_mutex;	/** task result queue mutex */
	pthread_mutex_t	timeout_mutex;	/** task timeout queue mutex */

	pthread_cond_t	worker_cond;	/** free worker cond */
	pthread_cond_t	exit_cond;	/** tpool exit cond */
	pthread_cond_t	wait_cond;	/** tpool wait for all thread free cond */
	pthread_cond_t	result_cond;	/** task generate result condition */
	pthread_cond_t	timeout_cond;	/** task timeout condition */

	uint32_t	cur_num;	/** tpool current workers */
	uint32_t	max_num;	/** tpool max workers */
	uint32_t	free_num;	/** tpool free workers */

	/** task related arguments */
	uint32_t	task_num;	/** task stack number */
	list_head_t	task_head;	/** task stack head */
	uint32_t	task_res_num;	/** task result number */
	list_head_t	task_res_head;	/** task result stack */
	uint32_t	task_to_num;	/** task timeout number */
	list_head_t	task_to_head;	/** task timeout stack */

	void		*def_task_arg;	/** default task argument */
	dlib_task_fn	def_task_cb;	/** default task function */
	uint32_t	def_timeout;	/** default task timeout time */
	void		*def_totask_arg;/** default task timeout argument */
	dlib_totask_fn	def_totask_cb;	/** default task timeout function */
	void		*def_detask_arg;/** default task destructure argument */
	dlib_detask_fn	def_detask_cb;	/** default task finished function */

	/** worked in specail situation, like persist-links for each thread */
	void		*def_tinit_arg;	/** init function arg */
	dlib_tinit_fn	def_tinit_cb;	/** init function for each thread */
	dlib_texit_fn	def_texit_cb;	/** exit function for each thread */

	dlib_titem_t	*tp_threads;	/** thread items */
};

static uint32_t tp_id = 0;

/**
 * _tpool_worker
 * @brief the workers employed by tpool
 * @param arg: worker tools
 */
static void *_tpool_worker(void *arg);

static void *_tpool_worker(void *arg)
{
	dlib_tpool_t *tp;
	dlib_task_t *task = NULL;
	int flag = 0;
	list_node_t *pos = NULL;
	dlib_task_t *tpos = NULL;

#ifdef _DEBUG
	uint32_t num = 0;
	struct timeval start;
	struct timeval end;
	struct timeval tmp;
#endif

	if (arg == NULL)
		return NULL;
	tp = (dlib_tpool_t *)arg;

#ifdef _DEBUG
	/* restore the number of current thread */
	num = tp->cur_num;
#endif

	tp->cur_num++;
	tp->free_num++;

	pthread_mutex_unlock(&(tp->worker_mutex));

	/** init the thread */
	if (tp->def_tinit_cb != NULL)
		tp->tp_threads[num].thread_data = (*tp->def_tinit_cb)(tp->def_tinit_arg);

	/** waiting for task, until received exit command */
	while (tp->status != TP_EXIT) {
		if (flag == 0) {
			flag = 1;
		} else {
			pthread_mutex_lock(&(tp->worker_mutex));
			tp->free_num++;
			pthread_cond_signal(&(tp->wait_cond));
			pthread_mutex_unlock(&(tp->worker_mutex));
		}

		pthread_mutex_lock(&(tp->task_mutex));
		while (tp->task_num == 0 && tp->status != TP_EXIT) {
			pthread_cond_wait(&(tp->worker_cond), &(tp->task_mutex));
		}
		/** worker was fired by tpool, then quit directly */
		if (tp->status == TP_EXIT) {
			pthread_mutex_unlock(&(tp->task_mutex));
			break;
		}

		pthread_mutex_lock(&(tp->worker_mutex));
		tp->free_num--;
		pthread_mutex_unlock(&(tp->worker_mutex));

		/** debug for a long time while unit-test threadpool module */
		LIST_POP_ENTRY(task, &tp->task_head, node);
		tp->task_num--;

		pthread_mutex_unlock(&(tp->task_mutex));

		/** execute task and then free task structs out of locks */
#ifdef _DEBUG
		tp->tp_threads[num].statics.count++;
		DLIB_UTIMER_RECORD(&start);
#endif
		task->task_res = (*task->task_cb)(tp->tp_threads[num].thread_data, task->task_arg);
		if (task->task_res == NULL) {
			/** not care about task result */
			dfree(task);
		} else {
			/** timeout or success return */
			if ((task->task_timeout != 0) && (time(NULL) -
					task->task_start > task->task_timeout)) {
				/** timeout */
				pthread_mutex_lock(&tp->timeout_mutex);
				LIST_FOREACH_ENTRY_PREV(tpos, pos, &tp->task_to_head, node) {
					if (tpos->task_nice <= task->task_nice)
						break;
				}
				if (pos == &tp->task_to_head) { /** add to list head */
					LIST_ADD_HEAD(&tp->task_to_head, &task->node);
				} else { /** add after tpos */
					LIST_INSERT_AFTER(&tpos->node, &task->node);
				}

				/** cause a timeout event */
				tp->task_to_num++;
				pthread_cond_signal(&tp->timeout_cond);
				pthread_mutex_unlock(&tp->timeout_mutex);
			} else {
				/** success return */
				pthread_mutex_lock(&tp->result_mutex);
				LIST_FOREACH_ENTRY_PREV(tpos, pos, &tp->task_res_head, node) {
					if (tpos->task_nice <= task->task_nice)
						break;
				}
				if (pos == &tp->task_res_head) { /** add to list head */
					LIST_ADD_HEAD(&tp->task_res_head, &task->node);
				} else { /** add after tpos */
					LIST_INSERT_AFTER(&tpos->node, &task->node);
				}

				/** cause a success-return event */
				tp->task_res_num++;
				pthread_cond_signal(&tp->result_cond);
				pthread_mutex_unlock(&tp->result_mutex);
			} /* end if timeout */
		} /* end task result judgement */
#ifdef _DEBUG
		DLIB_UTIMER_RECORD(&end);
		DLIB_UTIMER_SUB(&end, &start, &tmp);
		DLIB_UTIMER_ADD(&tmp, &(tp->tp_threads[num].statics.tv),
			   &(tp->tp_threads[num].statics.tv));
#endif
	} /* end while */

	/** worker is fired, cause to exit and cleanup */
	if (tp->def_texit_cb != NULL)
		(void)(*tp->def_texit_cb)(tp->tp_threads[num].thread_data);
	
	pthread_mutex_lock(&(tp->worker_mutex));
	tp->free_num--;
	tp->cur_num--;
	pthread_cond_signal(&(tp->exit_cond));
	pthread_mutex_unlock(&(tp->worker_mutex));

	pthread_exit(NULL);
}

dlib_tpool_t *dlib_tpool_init(uint32_t init_num, uint32_t max_num, 
			      dlib_tinit_fn tinit_cb, void *tinit_arg,
			      dlib_texit_fn texit_cb)
{
	uint32_t i;
	uint32_t count = 0;
	dlib_tpool_t *tp;

	if (max_num == 0)
		return NULL;
	if (init_num == 0 || init_num > max_num)
		init_num = max_num;

	tp = (dlib_tpool_t *)dmalloc(sizeof (*tp));
	tp->tp_id = tp_id++;
	tp->tp_threads = (dlib_titem_t *)dmalloc(max_num * sizeof(dlib_titem_t));
	/**
	 * TP_WORK means tpool waiting for task,
	 * TP_EXIT means tpool waiting for exit
	 */
	tp->status = TP_WORK;

	pthread_attr_init(&tp->tp_attr);
	pthread_attr_setdetachstate(&tp->tp_attr, PTHREAD_CREATE_DETACHED);

	pthread_mutex_init(&(tp->worker_mutex), NULL);
	pthread_mutex_init(&(tp->task_mutex), NULL);
	pthread_mutex_init(&(tp->result_mutex), NULL);
	pthread_mutex_init(&(tp->timeout_mutex), NULL);

	pthread_cond_init(&(tp->worker_cond), NULL);
	pthread_cond_init(&(tp->exit_cond), NULL);
	pthread_cond_init(&(tp->wait_cond), NULL);
	pthread_cond_init(&(tp->result_cond), NULL);
	pthread_cond_init(&(tp->timeout_cond), NULL);

	tp->max_num = max_num;
	tp->cur_num = 0;
	tp->free_num = 0;

	tp->task_num = 0;
	LIST_HEAD_INIT(&tp->task_head);
	tp->task_res_num = 0;
	LIST_HEAD_INIT(&tp->task_res_head);
	tp->task_to_num = 0;
	LIST_HEAD_INIT(&tp->task_to_head);

	tp->def_task_arg = NULL;
	tp->def_task_cb = NULL;
	tp->def_timeout = 0;
	tp->def_totask_arg = NULL;
	tp->def_totask_cb = NULL;
	tp->def_detask_arg = NULL;
	tp->def_detask_cb = NULL;

	tp->def_tinit_arg = tinit_arg;
	tp->def_tinit_cb = tinit_cb;
	tp->def_texit_cb = texit_cb;

	/** employ init_num workers */
	for (i = 0; i < init_num; i++) {
		/** locked before pthread_create and unlock in _tpool_worker */
		pthread_mutex_lock(&(tp->worker_mutex));
		if (pthread_create(&(tp->tp_threads[i].pid), &tp->tp_attr,
					_tpool_worker, tp) == 0) {
			count++;
		} else {
			pthread_mutex_unlock(&(tp->worker_mutex));
		}
	}

	/** all threads create fail */
	if (count == 0) {
		pthread_mutex_destroy(&(tp->worker_mutex));
		pthread_mutex_destroy(&(tp->task_mutex));
		pthread_mutex_destroy(&(tp->result_mutex));
		pthread_mutex_destroy(&(tp->timeout_mutex));

		pthread_cond_destroy(&(tp->worker_cond));
		pthread_cond_destroy(&(tp->exit_cond));
		pthread_cond_destroy(&(tp->wait_cond));
		pthread_cond_destroy(&(tp->result_cond));
		pthread_cond_destroy(&(tp->timeout_cond));

		dfree(tp->tp_threads);
		dfree(tp);

		return NULL;
	}

	return tp;
}

int dlib_tpool_settask(dlib_tpool_t *tp, dlib_task_fn task_cb, void *task_arg)
{
	if (tp == NULL || task_cb == NULL)
		return -1;
	tp->def_task_cb = task_cb;
	tp->def_task_arg = task_arg;
	return 0;
}

int dlib_tpool_settotask(dlib_tpool_t *tp, uint32_t timeout,
			 dlib_totask_fn totask_cb, void *totask_arg)
{
	if (tp == NULL || totask_cb == NULL)
		return -1;
	tp->def_timeout = timeout;
	tp->def_totask_cb = totask_cb;
	tp->def_totask_arg = totask_arg;
	return 0;
}

int dlib_tpool_setdetask(dlib_tpool_t *tp, dlib_detask_fn detask_cb, void *detask_arg)
{
	if (tp == NULL || detask_cb == NULL)
		return -1;
	tp->def_detask_cb = detask_cb;
	tp->def_detask_arg = detask_arg;
	return 0;
}

int dlib_tpool_execute(dlib_tpool_t *tp, uint32_t tnice,
		       dlib_task_fn task_cb, void *task_arg)
{
	if (tp == NULL)
		return -1;
	if (task_cb == NULL)
		task_cb = tp->def_task_cb;
	if (task_arg == NULL)
		task_arg = tp->def_task_arg;	
	return dlib_tpool_execute9(tp, tnice, task_cb, task_arg, tp->def_timeout,
			tp->def_totask_cb, tp->def_totask_arg, tp->def_detask_cb,
			tp->def_detask_arg);
}

int dlib_tpool_execute9(dlib_tpool_t *tp, uint32_t tnice, dlib_task_fn task_cb,
			void *task_arg, uint32_t timeo, dlib_totask_fn totask_cb,
			void *totask_arg, dlib_detask_fn detask_cb,
			void *detask_arg)
{
	dlib_task_t *task = NULL;
	list_node_t *pos = NULL;
	dlib_task_t *tpos = NULL;

	if (tp == NULL || task_cb == NULL)
		return -1;

	/** submit task */
	task = (dlib_task_t *)dmalloc_nb(sizeof (*task));
	if (task == NULL) {
		return -2;
	}
	task->task_nice = tnice;
	task->task_cb = task_cb;
	task->task_arg = task_arg;
	task->task_timeout = timeo;
	task->task_start = time(NULL);
	task->totask_arg = totask_arg;
	task->totask_cb = totask_cb;
	task->detask_arg = detask_arg;
	task->detask_cb = detask_cb;
	task->task_res = NULL;

	/** there is no free workers and worker number doesn't supstandard */
	pthread_mutex_lock(&(tp->worker_mutex));
	if (tp->free_num == 0 && tp->cur_num < tp->max_num) {
		if (pthread_create(&(tp->tp_threads[tp->cur_num].pid), &tp->tp_attr,
				   _tpool_worker, tp) == 0) {
			pthread_mutex_lock(&(tp->worker_mutex));
		}
	}
	pthread_mutex_unlock(&(tp->worker_mutex));

	pthread_mutex_lock(&(tp->task_mutex));
	/** look for a suitable task for scheduling */
	LIST_FOREACH_ENTRY_PREV(tpos, pos, &tp->task_head, node) {
		if (tpos->task_nice <= task->task_nice)
			break;
	}
	/** add to list head */
	if (pos == &tp->task_head) {
		LIST_ADD_HEAD(&tp->task_head, &task->node);
	} else { /** add after tpos */
		LIST_INSERT_AFTER(&tpos->node, &task->node);
	}

	/** schedule a worker */
	tp->task_num++;
	pthread_cond_signal(&(tp->worker_cond));
	pthread_mutex_unlock(&(tp->task_mutex));

	return 0;
}

void *dlib_tpool_timeout(dlib_tpool_t *tp)
{
	void *ret = NULL;
	dlib_task_t *task;

	if (tp == NULL)
		return NULL;

	while (tp->status != TP_EXIT) {
		pthread_mutex_lock(&tp->timeout_mutex);
		while (tp->task_to_num == 0 && tp->status != TP_EXIT) {
			pthread_cond_wait(&tp->timeout_cond, &tp->timeout_mutex);
		}
		if (tp->status == TP_EXIT) {
			pthread_mutex_unlock(&tp->timeout_mutex);
			break;
		}

		/** pickup a timeout task, and invoke timeout callback */
		LIST_POP_ENTRY(task, &tp->task_to_head, node);
		tp->task_to_num--;

		pthread_mutex_unlock(&tp->timeout_mutex);
		
		if (task->totask_cb != NULL) {
			ret = (*(task->totask_cb))(task->task_res, task->totask_arg);
		}
		dfree(task);
	}
	
	return ret;
}

int dlib_tpool_timeout_async(dlib_tpool_t *tp)
{
	pthread_t pid;

	if (tp == NULL) {
		return -1;
	}
	if (pthread_create(&pid, &tp->tp_attr, 
			(void *(*)(void *))dlib_tpool_timeout, (void *)tp) != 0) {
		return -2;
	}

	return 0;
}

void *dlib_tpool_retrieve(dlib_tpool_t *tp)
{
	void *ret = NULL;
	dlib_task_t *task;

	if (tp == NULL)
		return NULL;

	while (tp->status != TP_EXIT) {
		pthread_mutex_lock(&tp->result_mutex);
		while (tp->task_res_num == 0 && tp->status != TP_EXIT) {
			pthread_cond_wait(&tp->result_cond, &tp->result_mutex);
		}
		if (tp->status == TP_EXIT) {
			pthread_mutex_unlock(&tp->result_mutex);
			break;
		}

		/** pickup a timeout task, and invoke timeout callback */
		LIST_POP_ENTRY(task, &tp->task_res_head, node);
		tp->task_res_num--;

		pthread_mutex_unlock(&tp->result_mutex);
		
		if (task->detask_cb != NULL) {
			ret = (*(task->detask_cb))(task->task_res, task->detask_arg);
		}
		dfree(task);
	}

	return ret;
}

int dlib_tpool_retrieve_async(dlib_tpool_t *tp)
{
	pthread_t pid;

	if (tp == NULL) {
		return -1;
	}
	if (pthread_create(&pid, &tp->tp_attr, 
			(void *(*)(void *))dlib_tpool_retrieve, (void *)tp) != 0) {
		return -2;
	}

	return 0;
}

void *dlib_tpool_wait(dlib_tpool_t *tp)
{
	if (tp == NULL)
		return NULL;

	/** task_num is not protected by mutex */
	while(tp->task_num != 0);
	/** wait for all thread done */

	pthread_mutex_lock(&(tp->worker_mutex));
	while (tp->free_num != tp->cur_num) {
		pthread_cond_wait(&(tp->wait_cond), &(tp->worker_mutex));
	}
	pthread_mutex_unlock(&(tp->worker_mutex));

	/** wait for timeout handle done, task_to_num is not protected by mutex */
	while(tp->task_to_num != 0);

	/** wait for result handle done, task_res_num is not protected by mutex */
	while(tp->task_res_num != 0);

	return NULL;
}

void dlib_tpool_exit(dlib_tpool_t *tp)
{
	dlib_task_t *tpos = NULL;
	list_node_t *pos, *n;
	if (tp == NULL)
		return;

	/** cause threads/timeout/retrieve exit */
	tp->status = TP_EXIT;

	/** cause result thread down */
	pthread_mutex_lock(&tp->result_mutex);
	pthread_cond_signal(&tp->result_cond);
	pthread_mutex_unlock(&tp->result_mutex);

	/** cause timeout thread down */
	pthread_mutex_lock(&tp->timeout_mutex);
	pthread_cond_signal(&tp->timeout_cond);
	pthread_mutex_unlock(&tp->timeout_mutex);

	/** waiting for all pthread out */
	pthread_mutex_lock(&(tp->worker_mutex));
	while (tp->cur_num > 0) {
		pthread_cond_broadcast(&(tp->worker_cond));
		pthread_cond_wait(&(tp->exit_cond), &(tp->worker_mutex));
	}
	pthread_mutex_unlock(&(tp->worker_mutex));

	/** cleanup task queue, move task to timeout */
	pthread_mutex_lock(&tp->task_mutex);
	LIST_FOREACH_ENTRY_PREV_SAFE(tpos, pos, n, &tp->task_head, node) {
		LIST_DEL(&tpos->node);
		tp->task_num--;
		if (tpos->totask_cb != NULL) {
			(void)(*(tpos->totask_cb))(tpos->task_res, tpos->totask_arg);
		}
		dfree(tpos);
	}
	pthread_mutex_unlock(&tp->task_mutex);

	/** cleanup timeout queue */
	pthread_mutex_lock(&tp->timeout_mutex);
	LIST_FOREACH_ENTRY_PREV_SAFE(tpos, pos, n, &tp->task_to_head, node) {
		LIST_DEL(&tpos->node);
		tp->task_to_num--;
		if (tpos->totask_cb != NULL) {
			(void)(*(tpos->totask_cb))(tpos->task_res, tpos->totask_arg);
		}
		dfree(tpos);
	}
	pthread_mutex_unlock(&tp->timeout_mutex);

	/** cleanup result queue */
	pthread_mutex_lock(&tp->result_mutex);
	LIST_FOREACH_ENTRY_PREV_SAFE(tpos, pos, n, &tp->task_res_head, node) {
		LIST_DEL(&tpos->node);
		tp->task_res_num--;
		if (tpos->detask_cb != NULL) {
			(void)(*(tpos->detask_cb))(tpos->task_res, tpos->detask_arg);
		}
		dfree(tpos);
	}
	pthread_mutex_unlock(&tp->result_mutex);

	pthread_attr_destroy(&tp->tp_attr);

	pthread_mutex_destroy(&(tp->worker_mutex));
	pthread_mutex_destroy(&(tp->task_mutex));
	pthread_mutex_destroy(&(tp->result_mutex));
	pthread_mutex_destroy(&(tp->timeout_mutex));

	pthread_cond_destroy(&(tp->worker_cond));
	pthread_cond_destroy(&(tp->exit_cond));
	pthread_cond_destroy(&(tp->wait_cond));
	pthread_cond_destroy(&(tp->result_cond));
	pthread_cond_destroy(&(tp->timeout_cond));

	dfree(tp->tp_threads);
	dfree(tp);
	return;
}

void dlib_tpool_dump(dlib_tpool_t *tp, FILE *fd)
{
	uint32_t i;

	if (fd == NULL)
		fd = stdout;
	pthread_mutex_lock(&tp->worker_mutex);
	fprintf(fd, "TPOOL dump out:\n"
		"    tp_id		: %u\n"
		"    status 		: %d\n"
		"    cur_num		: %u\n"
		"    max_num		: %u\n"
		"    free_num		: %u\n"
		"    task_num		: %u\n"
		"    task_timeout_num	: %u\n"
		"    task_finished_num	: %u\n",
		tp->tp_id, tp->status, tp->cur_num,
		tp->max_num, tp->free_num, tp->task_num,
		tp->task_to_num, tp->task_res_num);

#ifdef _DEBUG
	for (i = 0; i < tp->max_num; i++) {
		fprintf(fd, "THREAD #%d[%lu]: server count %u, server time %u.%06ds:\n",
			i, tp->tp_threads[i].pid, tp->tp_threads[i].statics.count,
			(uint32_t)tp->tp_threads[i].statics.tv.tv_sec,
			(uint32_t)tp->tp_threads[i].statics.tv.tv_usec);
	}
#endif
	pthread_mutex_unlock(&tp->worker_mutex);
	fflush(fd);
	return;
}


/** threads cluster */
dlib_thread_t *dlib_threads_init(size_t thread_count, dlib_thread_fn task_cb, void *arg)
{
	uint32_t i;
	dlib_thread_t *threads = NULL;

	threads = (dlib_thread_t *)dmalloc(thread_count * sizeof(dlib_thread_t));

	for (i = 0; i < thread_count; ++i) {
		if(dlib_thread_new(threads + i, task_cb, arg) != 0) {
			dfree(threads);
			return NULL;
		}
	}
	return threads;
}

void dlib_threads_exit(dlib_thread_t *threads, size_t thread_count)
{
	uint32_t i;
	void *res;
	if (threads == NULL)
		return;
	for(i = 0; i < thread_count; ++i) {
		dlib_thread_del(threads + i);
		pthread_join(threads[i].tid, &res);
	}
	dfree(threads);
	threads = NULL;
	return;
}

int dlib_thread_new(dlib_thread_t *thread, dlib_thread_fn task_cb, void *arg)
{
	int ret;
	if (thread == NULL || task_cb == NULL)
		return -1;

	thread->tcb = task_cb;
	thread->thread_arg = arg;

	pthread_mutex_init(&thread->lock, NULL);
	pthread_mutex_lock(&thread->lock);
	if((ret = pthread_create(&thread->tid, NULL, thread->tcb, thread)) != 0) {
		pthread_mutex_unlock(&thread->lock);
		pthread_mutex_destroy(&thread->lock);
		return ret;
	}
	thread->status = thread_running;
	pthread_mutex_unlock(&thread->lock);

	return 0;
}

int dlib_thread_del(dlib_thread_t *thread)
{
	int ret;
	if (thread == NULL)
		return -1;

	switch (thread->status) {
		case thread_fini:
			return 0;
		case thread_running:
			ret = pthread_cancel(thread->tid);
			if(ret == 0) {
				pthread_mutex_destroy(&thread->lock);
				thread->status = thread_fini;
			}
			return ret;
		default:
			return -1;
	}
}

